from __future__ import (absolute_import, division,
                        print_function, unicode_literals)
from collections import namedtuple
from json import dumps, load
import json
from logging import setLoggerClass
from operator import inv
from re import I

from ansible.utils.vars import load_extra_vars, load_options_vars
__metaclass__ = type

import shutil

import ansible.constants as C
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.module_utils.common.collections import ImmutableDict
from ansible.inventory.manager import InventoryManager
from ansible.parsing.dataloader import DataLoader
from ansible.playbook.play import Play
from ansible.vars.manager import VariableManager
from ansible import context
from .callBackController import resultsCollectorJsonCallback

__all__ = ["adHocRunner", "playBookRunner"]

C.HOST_KEY_CHECKING = False


class adHocRunner(object):
    # adHoc 接口
    # callback函数
    resultsCallbackClass = resultsCollectorJsonCallback()

    def __init__(self,
                 connection='smart',
                 # 链接类型 local 本地;smart 远程ssh
                 remote_user=None,
                 # ssh 用户名
                 remote_password=None,
                 # ssh 密码 字典 key为conn_pass
                 private_key_file=None,
                 # 私有key
                 remote_port=None,
                 sudo=None,
                 sudo_user=None,
                 ask_sudo_pass=None,
                 module_path=None,
                 # 模块路径
                 become=None,
                 # 是否提权
                 become_method=None,
                 # 提权方式，默认sudo 或su
                 become_user=None,
                 # 提权后的用户，非登录用户
                 check=False,
                 diff=False,
                 listhosts=None,
                 listtasks=None,
                 listtags=None,
                 verbosity=3,
                 syntax=None,
                 start_at_task=None,
                 inventory=None, ):
        # 函数文档注释
        """
        初始化函数，定义的默认的选项值，
        在初始化的时候可以传参，以便覆盖默认选项的值
        """
        context.CLIARGS = ImmutableDict(
            connection=connection,
            remote_user=remote_user,
            private_key_file=private_key_file,
            sudo=sudo,
            sudo_user=sudo_user,
            ask_sudo_pass=ask_sudo_pass,
            module_path=module_path,
            become=become,
            become_method=become_method,
            become_user=become_user,
            verbosity=verbosity,
            listhosts=listhosts,
            listtasks=listtasks,
            listtags=listtags,
            syntax=syntax,
            start_at_task=start_at_task,
            remote_port=remote_port,
        )
        """
        三元表达式，假如没有传递 inventory, 就使用 "localhost,"
        指定 inventory 文件
        inventory 的值可以是一个 资产清单文件
        也可以是一个包含主机的元组，这个仅仅适用于测试
        比如 ： 1.1.1.1,    # 如果只有一个 IP 最后必须有英文的逗号
        或者： 1.1.1.1, 2.2.2.2
        """
        # 单独IP

        self.inventory = inventory if inventory else "localhost,"
        # 实例化数据解析器
        self.loader = DataLoader()
        # 实例化 资产配置对象
        self.inv_obj = InventoryManager(
            loader=self.loader, sources=self.inventory)
        # 设置密码
        self.passwords = dict(conn_pass=remote_password)
        # 实例化回调插件对象
        self.results_callback = self.resultsCallbackClass
        # 变量管理器
        self.variable_manager = VariableManager(
            loader=self.loader, inventory=self.inv_obj)
        # 定义一个命令执行的run

        print("nbbb", self.variable_manager)

    def palyRun(self, hosts='localhost', gather_facts="no", module="ping", args=''):
        """
        task_time -- 执行异步任务时等待的秒数，这个需要大于 0 ，等于 0 的时候不支持异步（默认值）。
        """
        play_source = dict(
            name="Ad-hoc",
            hosts=hosts,
            gather_facts=gather_facts,
            tasks=[
                {
                    "action": {
                        "module": module,
                        "args": args,

                    }
                }
            ]
        )
        play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)
        tqm = None
        try:
            # 通过队列执行单个命令
            tqm = TaskQueueManager(
                inventory=self.inv_obj,
                variable_manager=self.variable_manager,
                loader=self.loader,
                passwords=self.passwords,
                stdout_callback=self.resultsCallbackClass
            )

            result = tqm.run(play)

        finally:
            if tqm is not None:
                tqm.cleanup()
                shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)

    def playBook(self, playbooks):
        """
        Keyword arguments:
        playbooks --  需要是一个列表类型
        """
        from ansible.executor.playbook_executor import PlaybookExecutor
        playbook = PlaybookExecutor(playbooks=playbooks,
                                    inventory=self.inv_obj,
                                    variable_manager=self.variable_manager,
                                    loader=self.loader,
                                    passwords=self.passwords)

        playbook._tqm._stdout_callback = self.results_callback

        result = playbook.run()

        return result

    def getResult(self):
        # 定义接口状态
        resultRaw = {'success': {},
                     'failed': {},
                     'unreachable': {}}

        # 回调接口状态
        for host, result in self.results_callback.host_ok.items():
            resultRaw['success'][host] = result._result
        for host, result in self.results_callback.host_failed.items():
            resultRaw['failed'][host] = result._result
        for host, result in self.results_callback.host_unreachable.items():
            resultRaw['unreachable'][host] = result._result

        # 格式化json输出
        print(json.dumps(resultRaw, indent=4))
        return json.dumps(resultRaw)
